package com.snifferx.managedbeans;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.jboss.logging.Logger;
import org.primefaces.context.RequestContext;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;

import com.snifferx.domain.UserEntity;
import com.snifferx.services.UserAuthenticationProviderService;
import com.snifferx.services.UserService;
import com.snifferx.util.MessageDigestUtil;
import com.snifferx.util.RandomStringUtils;
import com.snifferx.util.helper.EmailHelper;

@ManagedBean(name = "loginBean")
@SessionScoped
// @Component
// @Scope("session")
// @Qualifier("loginBean")
public class LoginBean implements Serializable {
	private static final long serialVersionUID = 1L;

	private String login;
	private String password;

	private String msg;
	private User currentUserDetails;

	private int attemptTime;

	// @ManagedProperty(value = "#{authenticationService}")
	// private AuthenticationService authenticationService;

	@ManagedProperty(value = "#{authenticationService}")
	// @Autowired
	private UserAuthenticationProviderService authenticationService;

	// weicheng added for userInfo
	@ManagedProperty(value = "#{userService}")
	// @Autowired
	private UserService userService;
	UserEntity user;

	// for edit profile
	private StreamedContent image;
	private byte[] headshot;
	private String key;
	private static Logger log = Logger.getLogger(LoginBean.class);
	private String uploadFileName;

	private boolean authorities;

	private boolean showJcaptcha;

	private boolean adminAuthority;

	public String login() throws IOException {
		// 先判断filter的值
		// System.out.println("GET info :" +
		// FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("CaptchaException"));
		// boolean flag =
		// (FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("CaptchaException")
		// == null);
		boolean flag = (FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("CaptchaException") == null);
		// FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove("CaptchaException");
		FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove("CaptchaException");
		boolean success = false;
		if (flag) {

			// success = authenticationService.login(login, password);
			MessageDigestUtil messageDigestUtil = MessageDigestUtil.getInstance();
			String encryptedInputPassword;
			try {
				encryptedInputPassword = messageDigestUtil.encrypt(password);

				success = authenticationService.processUserAuthentication(login, encryptedInputPassword);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (success) {
			ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
			HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
			HttpSession session = request.getSession(false);
			HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
			if (session != null) {
				// String webContext = request.getContextPath();
				SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
				String url = null;
				if (savedRequest != null) {
					url = savedRequest.getRedirectUrl();
				} else {
					url = "http://localhost:7777/SnifferX";//will fix later
				}
				// get userDetails
				currentUserDetails = authenticationService.getUserdetails();
				user = userService.loadUserEntityByUsername(login);

				// set admin here
				Collection<GrantedAuthority> authoritiesDB = currentUserDetails.getAuthorities();
				RequestContext context = RequestContext.getCurrentInstance();
				if (authoritiesDB.size() != 0) {
					for (GrantedAuthority e : authoritiesDB) {
						if ("ROLE_ADMINISTRATOR".equals(e.toString())) {
							this.adminAuthority = true;
						}
					}
				}

				// String pathWithinContext =
				// url.substring(url.indexOf(webContext) + webContext.length());
				response.sendRedirect(url);
				return null;
				// logged now
			}
			return null;

		} else {

			attemptTime++;
			System.out.println("attemptTime :" + attemptTime);
			System.out.println(attemptTime == 4);
			if (attemptTime == 4) {
				this.showJcaptcha = true;
			}
			if (FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("DisabledException") != null) {

			} else if (flag) {
				// FacesContext.getCurrentInstance().addMessage(null, new
				// FacesMessage("Login or password incorrect."));
			} else {
				FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Wrong captcha text or expired."));
			}
			return "login.xhtml";
		}
	}

	public String triggerImage() {
		FacesContext context = FacesContext.getCurrentInstance();
		String baseURL = context.getExternalContext().getRequestContextPath();
		String url = baseURL + "/jcaptcha.jpg";

		/*
		 * try { //String encodeURL =
		 * context.getExternalContext().encodeResourceURL(url);
		 * //context.getExternalContext().redirect(url);
		 * context.getExternalContext().dispatch(url); } catch (Exception e) {
		 * // Handle the exception here ... } finally {
		 * context.responseComplete(); }
		 */
		return null;
		// if using login.xhtml , will disables all value which you enter before
		// return "login.xhtml";
	}

	/*
	 * public void triggerImageTest() {
	 * System.out.println(">> Into triggerImageTest() Method.....");
	 * FacesContext context = FacesContext.getCurrentInstance(); String baseURL
	 * = context.getExternalContext().getRequestContextPath(); String url =
	 * baseURL + "/jcaptcha.jpg";
	 * 
	 * 
	 * }
	 */

	// just active when is pring bean
	// @PreAuthorize("hasRole('ROLE_ADMINISTRATOR')")
	public void upload(ActionEvent e) {
		FileItem fileItem = (FileItem) FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().remove(key);
		if (fileItem != null) {
			try {
				byte[] data = fileItem.get();
				// this.headshot = data;
				this.user.setHeadshot(data);
				// ByteArrayInputStream stream = new ByteArrayInputStream(data);
				// this.setImage(new DefaultStreamedContent(stream,
				// "image/jpg"));

				this.uploadFileName = fileItem.getName();
			} catch (Exception ex) {
			}
		}
	}

	// active button
	public void setLock(ActionEvent event) {
		Collection<GrantedAuthority> authoritiesDB = currentUserDetails.getAuthorities();
		RequestContext context = RequestContext.getCurrentInstance();
		if (authoritiesDB.size() != 0) {
			for (GrantedAuthority e : authoritiesDB) {
				log.debug("get authority :" + e);
				if ("ROLE_ADMINISTRATOR".equals(e.toString())) {
					this.authorities = true;
					context.addCallbackParam("unlockFlag", true);
				}
			}
			if (!this.authorities) {
				log.debug("this account have no proper authority.");
				FacesContext.getCurrentInstance().addMessage(null,
						new FacesMessage(FacesMessage.SEVERITY_WARN, "this account have no proper authority.", ""));
				context.addCallbackParam("unlockFlag", false);
			}
			// this.authorities = true;
		} else {
			log.debug("this account have no authority.");
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "this account have no authority .", ""));
			context.addCallbackParam("unlockFlag", false);

		}
	}

	public String doUpdateInfo() {
		// update userInfo to DB
		this.userService.updateUserEntity(user);
		return null;
	}

	// for forward to login
	public String turnToLogin() {
		String mtdName = "turnToLogin()";
		return "/login";
	}

	public void setLockTest(ActionEvent event) {

		this.authorities = true;
	}

	@PostConstruct
	private void generateKey() {
		log.debug("Into  @PostConstruct Method()... ");
		key = UUID.randomUUID().toString();
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setAuthenticationService(UserAuthenticationProviderService authenticationService) {
		this.authenticationService = authenticationService;
	}

	public String getMsg() {
		if (FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("message") != null) {
			FacesContext.getCurrentInstance().addMessage(null,
					new FacesMessage(FacesMessage.SEVERITY_WARN, "You do not have permission to access this page.", ""));

			// sent to facesMessage to deal with ,then remove the value from
			// session
			FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove("message");
		}
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	/**
	 * @return the currentUserDetails
	 */
	public User getCurrentUserDetails() {
		return currentUserDetails;
	}

	/**
	 * @param currentUserDetails
	 *            the currentUserDetails to set
	 */
	public void setCurrentUserDetails(User currentUserDetails) {
		this.currentUserDetails = currentUserDetails;
	}

	public int getAttemptTime() {
		return attemptTime;
	}

	public void setAttemptTime(int attemptTime) {
		this.attemptTime = attemptTime;
	}

	public boolean isShowJcaptcha() {
		return showJcaptcha;
	}

	public void setShowJcaptcha(boolean showJcaptcha) {
		this.showJcaptcha = showJcaptcha;
	}

	public UserAuthenticationProviderService getAuthenticationService() {
		return authenticationService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public UserEntity getUser() {
		return user;
	}

	public void setUser(UserEntity user) {
		this.user = user;
	}

	public StreamedContent getImage() {
		if (this.image != null) {
			log.debug("headshot length:" + this.headshot.length);
			image = new DefaultStreamedContent(new ByteArrayInputStream(this.headshot), "image/png");
		}
		return image;
	}

	public void setImage(StreamedContent image) {
		this.image = image;
	}

	public byte[] getHeadshot() {
		return headshot;
	}

	public void setHeadshot(byte[] headshot) {
		this.headshot = headshot;
	}

	public String getUploadFileName() {
		return uploadFileName;
	}

	public void setUploadFileName(String uploadFileName) {
		this.uploadFileName = uploadFileName;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public boolean isAuthorities() {
		return authorities;
	}

	public void setAuthorities(boolean authorities) {
		this.authorities = authorities;
	}

	public boolean isAdminAuthority() {
		return adminAuthority;
	}

	public void setAdminAuthority(boolean adminAuthority) {
		this.adminAuthority = adminAuthority;
	}

}
